//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftServiceLifecycle open source project
//
// Copyright (c) 2023 Apple Inc. and the SwiftServiceLifecycle project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftServiceLifecycle project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(Musl)
import Musl
#elseif canImport(Android)
import Android
#endif
import Dispatch

/// A struct representing a Unix signal.
///
/// Signals are standardized messages sent to a running program to trigger specific behavior, such as quitting or error handling
public struct UnixSignal: Hashable, Sendable, CustomStringConvertible {
    internal enum Wrapped {
        case sigabrt
        case sighup
        case sigill
        case sigint
        case sigsegv
        case sigterm
        case sigusr1
        case sigusr2
        case sigalrm
        case sigquit
        case sigwinch
        case sigcont
        case sigpipe
    }

    private let wrapped: Wrapped
    private init(_ wrapped: Wrapped) {
        self.wrapped = wrapped
    }

    public var rawValue: Int32 {
        return self.wrapped.rawValue
    }

    public var description: String {
        return String(describing: self.wrapped)
    }

    /// Usually generated by the abort() function. Useful for cleanup prior to termination.
    public static let sigabrt = Self(.sigabrt)
    /// Hang up detected on controlling terminal or death of controlling process. # ignore-unacceptable-language
    public static let sighup = Self(.sighup)
    /// Issued if the user attempts to execute an illegal, malformed, or privileged instruction.
    public static let sigill = Self(.sigill)
    /// Issued if the user sends an interrupt signal.
    public static let sigint = Self(.sigint)
    /// Issued if the user sends a quit signal.
    public static let sigquit = Self(.sigquit)
    /// Issued if the user makes an invalid memory reference, such as dereferencing a null or invalid pointer.
    public static let sigsegv = Self(.sigsegv)
    /// Software termination signal.
    public static let sigterm = Self(.sigterm)
    public static let sigusr1 = Self(.sigusr1)
    public static let sigusr2 = Self(.sigusr2)
    public static let sigalrm = Self(.sigalrm)
    /// Signal when the window is resized.
    public static let sigwinch = Self(.sigwinch)
    public static let sigcont = Self(.sigcont)
    /// Signal when a write is performed on a closed fd
    public static let sigpipe = Self(.sigpipe)
}

extension UnixSignal.Wrapped: Hashable {}
extension UnixSignal.Wrapped: Sendable {}

extension UnixSignal.Wrapped: CustomStringConvertible {
    var description: String {
        switch self {
        case .sigabrt:
            return "SIGABRT"
        case .sighup:
            return "SIGHUP"
        case .sigill:
            return "SIGILL"
        case .sigint:
            return "SIGINT"
        case .sigquit:
            return "SIGQUIT"
        case .sigsegv:
            return "SIGSEGV"
        case .sigterm:
            return "SIGTERM"
        case .sigusr1:
            return "SIGUSR1"
        case .sigusr2:
            return "SIGUSR2"
        case .sigalrm:
            return "SIGALRM"
        case .sigwinch:
            return "SIGWINCH"
        case .sigcont:
            return "SIGCONT"
        case .sigpipe:
            return "SIGPIPE"
        }
    }
}

extension UnixSignal.Wrapped {
    var rawValue: Int32 {
        switch self {
        case .sigabrt:
            return SIGABRT
        case .sighup:
            return SIGHUP
        case .sigill:
            return SIGILL
        case .sigint:
            return SIGINT
        case .sigquit:
            return SIGQUIT
        case .sigsegv:
            return SIGSEGV
        case .sigterm:
            return SIGTERM
        case .sigusr1:
            return SIGUSR1
        case .sigusr2:
            return SIGUSR2
        case .sigalrm:
            return SIGALRM
        case .sigwinch:
            return SIGWINCH
        case .sigcont:
            return SIGCONT
        case .sigpipe:
            return SIGPIPE
        }
    }
}
